package com.huawang.mdesign.model.service.inter.override;

import com.huawang.business.constants.ErrorCode;
import com.huawang.business.exception.AbortExecutionException;
import com.huawang.business.service.model.core.InternalUmlService;
import com.huawang.business.service.model.core.project.ProjectManager;
import com.huawang.business.service.model.core.property.PropertyQueryParameter;
import com.huawang.business.service.model.core.property.SelectedElementCheck;
import com.huawang.business.vo.ModelResultVo;
import com.huawang.core.definition.mof.UMLDefinitionConstants;
import com.huawang.core.definition.mof.instances.MetaClassInstance;
import com.huawang.core.semantics.constants.ModelPackageNameConstants;
import com.huawang.mdesign.model.service.config.annotations.MofTransactional;
import com.huawang.mdesign.model.service.constant.ModelActionEnum;
import com.huawang.mdesign.model.service.constant.SpringBeanNameConstants;
import com.huawang.mdesign.model.service.dto.ModifyTableCellDto;
import com.huawang.mdesign.model.service.facade.property.IUpdateTableProperty;
import com.huawang.mdesign.model.service.facade.property.UAFPropertyOperations;
import com.huawang.mdesign.model.service.facade.property.UAFPropertyRemoveOperations;
import com.huawang.mdesign.model.service.facade.util.BatchQueryExecutor;
import com.huawang.mdesign.model.service.inter.ModelConstraintService;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Component;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;

import static com.huawang.mdesign.model.service.facade.util.BatchQueryExecutor.QUERY_PREFIX;

@Component(SpringBeanNameConstants.PROPERTY_MANAGER)
@Primary
public class UAFPropertyManager extends com.huawang.business.service.model.core.property.PropertyManager {

    private final UAFPropertyOperations operations;

    private final InternalUmlService internalUmlService;

    private IUpdateTableProperty updateTableProperty;

    private ModelConstraintService modelConstraintService;

    private final Map<String, Method> queryMethods;

    public UAFPropertyManager(UAFPropertyOperations propertyOperations,
                              ProjectManager projectManager,
                              InternalUmlService internalUmlService,
                              SelectedElementCheck selectedElementCheck,
                              UAFPropertyRemoveOperations propertyRemoveOperations,
                              IUpdateTableProperty updateTableProperty,
                              ModelConstraintService modelConstraintService) {
        super(propertyOperations, projectManager, internalUmlService, selectedElementCheck, propertyRemoveOperations);
        this.operations = propertyOperations;
        this.internalUmlService = internalUmlService;
        this.updateTableProperty = updateTableProperty;
        this.modelConstraintService = modelConstraintService;
        this.queryMethods = Arrays.stream(propertyOperations.getClass().getMethods())
                .filter(k -> k.getName().startsWith(QUERY_PREFIX))
                .collect(Collectors.toMap(Method::getName, k -> k, (i, j) -> j));
    }

    /**
     * 获得属性方法名称
     *
     * @param key
     * @param prefix
     * @param customizeMethod
     * @return
     */
    @Override
    public @NotNull String getPropertyMethodName(String key, @NotNull String prefix, String customizeMethod) {
        String method = super.getPropertyMethodName(key, prefix, customizeMethod);
        if (SpringBeanNameConstants.PROPERTY_OPERATION_METHODS_SET.contains(ModelPackageNameConstants.UAF + method)) {
            return ModelPackageNameConstants.UAF + method;
        }
        return method;
    }

    /**
     * 根据属性参数，获得属性值
     *
     * @param parameter
     * @return
     */
    @Override
    @Nullable
    public Object queryValue(PropertyQueryParameter parameter) {
        Method method = queryMethods.get(BatchQueryExecutor.getQueryMethod(parameter.getKey()));
        if (method == null) {
            return super.queryValue(parameter);
        } else {
            try {
                return method.invoke(this.operations, parameter);
            } catch (InvocationTargetException | IllegalAccessException var6) {
                throw AbortExecutionException.build(ErrorCode.PROPERTY_QUERY_ERROR, var6);
            }
        }
    }

    /**
     * 属性值新增或更新后
     */
    private void postPropertyAddOrUpdate(String projectId, String instanceId, String key, ModelResultVo modelResultVo) {
        MetaClassInstance slot = Optional.ofNullable(key)
                .filter(StringUtils::isNotBlank)
                .filter(e -> StringUtils.isNotBlank(instanceId))
                .filter(UMLDefinitionConstants.InstanceValue_instance::equals)
                .map(e -> internalUmlService.fetchInstance(instanceId, projectId))
                .map(MetaClassInstance::getOwnerId)
                .filter(StringUtils::isNotBlank)
                .map(e -> internalUmlService.fetchInstance(e, projectId))
                .orElse(UMLDefinitionConstants.Slot_value.equals(key) ?
                        internalUmlService.fetchInstance(instanceId, projectId) : null);

        Optional.ofNullable(slot)
                .map(MetaClassInstance::getOwnerId)
                .filter(StringUtils::isNotBlank)
                .map(e -> internalUmlService.fetchInstance(e, projectId))
                .filter(e -> CollectionUtils.isNotEmpty(e.getAppliedStereotypes()))
                .filter(e -> e.getAppliedStereotypes().contains(UMLDefinitionConstants.UAF_ActualProjectMilestone))
                .ifPresent(e ->
                        Optional.ofNullable(modelResultVo)
                                .map(ModelResultVo::getModifyModel)
                                .ifPresent(k -> k.add(e.getUUID()))
                );
    }

    /**
     * 更新表格单元
     *
     * @param model
     * @return
     */
    @MofTransactional(modelAction = ModelActionEnum.UPDATE_MODEL)
    @NotNull
    public ModelResultVo updateTableCell(ModifyTableCellDto model) {
        ModelResultVo modelResultVo = new ModelResultVo();
        updateTableProperty.updateTableCell(model);
        modelResultVo.setInstanceId(model.getInstanceId());
        postPropertyAddOrUpdate(model.getProjectId(), model.getInstanceId(), model.getKey(), modelResultVo);
        return modelResultVo;
    }

}
